package com.tju.resource.business.tb_command;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tju.resource.mapper.*;
import com.tju.resource.model.*;
import com.tju.resource.result.Result;
import com.tju.resource.result.ResultEnum;
import com.tju.resource.result.ResultUtil;
import com.tju.resource.tool.tool.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.math.RoundingMode;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;

import static com.tju.resource.tool.tool.WeightParser.*;


import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class TbCommandServiceImpl implements TbCommandService {

    private static int cmdNumberIndex = 0; //指令下标
    //SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    @Autowired
    private TbCommandMapper tbCommandMapper;
    @Autowired
    private TbCmdOrderMapper tbCmdOrderMapper;
    @Autowired
    private TbOrderMapper tbOrderMapper;
    // @Autowired
    //private SysParamsService paramsServiceService;
    @Autowired
    private ChineseExceptionUtils zh_CH;
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private TbRawMatlMapper tbRawMatlMapper;
    @Autowired
    private TbMatlConsumablesMapper tbMatlConsumablesMapper;
//    @Autowired
//    private TbOrderService tbOrderService;

    /**
     * 新增指令信息
     *
     * @param command 指令信息
     * @return 结果
     */
    @Override
    @Transactional
    public Result<Object> insertCommand(TbCommand command) {
        try {
            String cmdNumber = command.getCmdNumber(); //指令号
            String createBy = command.getCreateBy();//创建人
            //TbOrder tbOrder = tbOrderService.checkOrderNumberUnique(command.getOrderNumber());
//            long data = (command.getDelivery().getTime() - sdf.parse(sdf.format(new Date())).getTime()) / (24 * 3600 * 1000);  //算出来距离几天
//            long paramsValue = Long.parseLong(paramsServiceService.get("CMD_DELIVERY").getParamsValue());  //拿到你设置多少天交期
//            if (data < paramsValue) {
//                return ResultUtil.success(ResultEnum.UNKONW_ERROR, "交期时间必须大于指令时间：" + paramsValue + "天");
//            }
//            if (EmptyUtils.isNotEmpty(checkCommandNumberUnique(cmdNumber))) { //判断不为空进入
//                return ResultUtil.error(ResultEnum.UNKONW_ERROR, "指令号重复了：" + cmdNumber);
//            }
//            if (EmptyUtils.isEmpty(tbOrder)) {
//                return ResultUtil.error(ResultEnum.UNKONW_ERROR, "订单号不存在：" + command.getOrderNumber());
//            }
            if (EmptyUtils.isEmpty(cmdNumber) || EmptyUtils.isNotEmpty(checkCommandNumberUnique(cmdNumber))) {  //判断指令号为空或者重复的话就重新生产
                if (EmptyUtils.isNotEmpty(createBy)) {
                    while (true) {
                        String username = Objects.requireNonNull(QuickQuery.byOne(sysUserMapper, "username", createBy)).getDivCode();
                        if (EmptyUtils.isEmpty(checkCommandNumberUnique(cmdNumber(username)))) {//判断唯一
                            command.setCmdNumber(cmdNumber(username));
                            break;
                        }
                    }
                } else {
                    return ResultUtil.error(ResultEnum.UNKONW_ERROR, zh_CH.MissingParameters);
                }
            }
            if (tbCommandMapper.insert(command) > 0) {
                Long[] orderId = command.getOrderId();  //拿到订单的id
                if (EmptyUtils.isNotEmpty(orderId)) {      //判断不为空进入
                    TbCmdOrder cmdOrder;
                    for (Long orderValue : orderId) {  //循环订单id
                        cmdOrder = new TbCmdOrder();
                        cmdOrder.setCmdId(command.getId());  //添加指令号的id
                        cmdOrder.setOid(orderValue);  //添加订单的id
                        tbCmdOrderMapper.insert(cmdOrder);  //添加
                    }
                    return ResultUtil.success(ResultEnum.SUCCESS, zh_CH.AddedSuccessfully);
                } else {
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    return ResultUtil.error(ResultEnum.UNKONW_ERROR, "请选择指令所需订单!");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ResultUtil.error(ResultEnum.UNKONW_ERROR, zh_CH.AddFailed);
    }

    /**
     * 修改指令信息
     *
     * @param command 指令信息
     * @return 结果
     */
    @Override
    @Transactional
    public Result<Object> updateCommand(TbCommand command) {
        Long id = command.getId();  //拿到修改指令的id
        TbCommand tbCommand = tbCommandMapper.selectById(id); //查询修改指令的指令管理
//        TbOrder tbOrder = tbOrderService.checkOrderNumberUnique(command.getOrderNumber()); //根据订单号查询订单信息
//        if (EmptyUtils.isEmpty(tbOrder)) { //订单号不存在
//            return ResultUtil.error(ResultEnum.UNKONW_ERROR, "订单号不存在：" + command.getOrderNumber());
//        }
        if (EmptyUtils.isNotEmpty(tbCommand)) { //判断指令号不等于空
//                long data = (command.getDelivery().getTime() - sdf.parse(sdf.format(tbCommand.getCreateTime())).getTime()) / (24 * 3600 * 1000);  //算出来距离几天
//                long paramsValue = Long.parseLong(paramsServiceService.get("CMD_DELIVERY").getParamsValue());  //交期
//                if (data < paramsValue) {
//                    return ResultUtil.success(ResultEnum.UNKONW_ERROR, "交期时间必须大于指令时间：" + paramsValue + "天");
//                }
            //指令号不一样
            //判断不为空进入
            if (!tbCommand.getCmdNumber().equals(command.getCmdNumber()))
                if (EmptyUtils.isNotEmpty(checkCommandNumberUnique(command.getCmdNumber())))
                    return ResultUtil.error(ResultEnum.UNKONW_ERROR, "指令号重复了：" + command.getCmdNumber());
            if (tbCommandMapper.updateById(command) > 0) { //修改成功

                long tbOrderCount = 0L;  //计算订单id相等数
                Long[] orderId = command.getOrderId(); //拿到订单id
                if (EmptyUtils.isEmpty(orderId)) {
                    return ResultUtil.error(ResultEnum.UNKONW_ERROR, "请选择指令所需订单!");
                }
                List<TbCmdOrder> tbOrderList = new CopyOnWriteArrayList<>(listTbCmdOrderByCmdId(command.getId())); //查询指令下的订单
                for (TbCmdOrder tb : tbOrderList) { //循环原先的订单id
                    for (Long orderValueId : orderId) { //循环传来的订单id
                        if (tb.getOid().equals(orderValueId)) { //判断相等
                            tbOrderList.remove(tb); //删除
                            tbOrderCount++; //加加
                        } else tbCmdOrderMapper.deleteById(tb.getId()); //不相等就删除之前的
                    }
                }
                if (tbOrderCount != orderId.length) { //如果一样就证明没修改过
                    tbOrderList = new CopyOnWriteArrayList<>(listTbCmdOrderByCmdId(command.getId())); //在查询一次订单下物料id
                    int result; //状态
                    TbCmdOrder TbCmdOrder; //关联表
                    for (Long orderValueId : orderId) { //循环传来的
                        result = 0;
                        for (TbCmdOrder tb : tbOrderList) { //循环原先的
                            if (tb.getOid().equals(orderValueId)) { //判断相等
                                result = 1; //就等于1
                                break;
                            }
                        }
                        if (result != 1) { //相等的不添加
                            TbCmdOrder = new TbCmdOrder(); //添加关联表
                            TbCmdOrder.setCmdId(command.getId());  //指令id
                            TbCmdOrder.setOid(orderValueId); //订单id
                            tbCmdOrderMapper.insert(TbCmdOrder);//添加关联表
                        }
                    }
                }
                return ResultUtil.success(ResultEnum.SUCCESS, zh_CH.SuccessfullyModified);
            }
        } else {
            return ResultUtil.error(ResultEnum.UNKONW_ERROR, "指令不存在!");
        }
        return ResultUtil.error(ResultEnum.UNKONW_ERROR, zh_CH.FailToEdit);
    }

    /**
     * 查询指令信息
     *
     * @param param 指令信息
     * @return 结果
     */
    @Override
    public Result<Object> selectCommandList(Map<String, String> param) {
        try {
            int pageNum = Integer.parseInt(param.get("page"));  //页码
            int limit = Integer.parseInt(param.get("limit")); //页数量
            if (EmptyUtils.isNotEmpty(pageNum) && EmptyUtils.isNotEmpty(limit)) {  //不等于空
//                Long[] prodId;
                Page<TbCommand> page = new Page<>(pageNum, limit); //分页
                IPage<TbCommand> iPage = tbCommandMapper.selectCommandList(page, param); //分页查询
                List<TbOrder> orderList; //创建订单计划
                List<TbMaterial> listMaterial; //创建物料
                List<TbCommand> records = new CopyOnWriteArrayList(iPage.getRecords());//指令列表
                for (TbCommand command : records) { //循环指令
                    orderList = new CopyOnWriteArrayList(tbCommandMapper.getOrderList(command.getId(), param.get("orderNumber"))); //查询指令下的订单,并赋值
                    command.setTbOrderList(orderList); //把订单添加到指令
                    if (EmptyUtils.isEmpty(orderList)) { //没有该订单就不查询出来
                        records.remove(command);  //清空
                        continue; //下一个循环
                    }
                    for (TbOrder tbOrder : orderList) { //循环订单
                        Long orderPcsTotal = 0L; //计划数
                        listMaterial = new CopyOnWriteArrayList(tbCommandMapper.getListMaterial(tbOrder.getId(), param.get("matlNumber"))); //查询订单下的物料
                        if (EmptyUtils.isEmpty(listMaterial)) { //没有该物料就不查询出来
                            records.remove(command);  //清空
                            orderList.remove(tbOrder);  //清空
                            continue; //下一个循环
                        }
                        tbOrder.setTbMaterial(listMaterial); //把物料添加到订单
                        //订单数不为空
                        for (TbMaterial material : listMaterial) //循环物料
                        {
                            String matlUnit = material.getMatlUnit();  //物料单位
                            //int matlUnitWeight=matlUnit.equals("KG")?1000:matlUnit.equals("t")?10000000:1;
                            long orderPcs = material.getOrderPcs();  //订单数
                            long finishQuantity = EmptyUtils.isEmpty(material.getFinishQuantity()) ? 0 : material.getFinishQuantity();  //完成数量
                            long fpPcs = EmptyUtils.isEmpty(material.getFpPcs()) ? 0L : material.getFpPcs(); //成品数量
                            double wdWeight = EmptyUtils.isEmpty(material.getWdWeight()) ? 0.0 : material.getWdWeight();//水口重量
                            double matlWeight = EmptyUtils.isEmpty(material.getMatlWeight()) ? 0.0 : material.getMatlWeight();//物料单重
                            double weight = new BigDecimal(Double.toString(matlWeight)).add(new BigDecimal(Double.toString(wdWeight))).doubleValue();
                            double needWeight = weight * (orderPcs - fpPcs - finishQuantity);  //缺少重量
                            material.setNeedWeight(orderPcs <= fpPcs ? 0.0 : needWeight < 0 ? 0 : needWeight); //判断订单数小于成品需要数为0.0否者就水口重量+物料单重乘订单-成品数量
                            long lackPcs = orderPcs - fpPcs - finishQuantity;  //订单缺少数量
                            lackPcs = Math.max(lackPcs, 0L); //判断缺少数量
                            material.setLackPcs(orderPcs <= fpPcs ? 0 : lackPcs < 0 ? 0 : lackPcs); //判断订单数小于成品需要数为0
                            material.setWeight(weight * orderPcs); //所有重量
                            material.setUnFinishQuantity(orderPcs - finishQuantity);  //未完成数量
                            List<TbRawMatl> rawMatlList = tbRawMatlMapper.selectTbRawMatlById(null, material.getId());

                            for (TbRawMatl rmMatl : rawMatlList) {
                                int type = rmMatl.getRmType(); //类型
                                //物料缺重+换算单位
                                Double deficiencyWeight = parse(needWeight, toUnit(matlUnit), toUnit(rmMatl.getRmUnit()));
                                double rmStoke = rmMatl.getRmStoke(); //库存
                                int reMatlNumber = 0; // 缺少数量
                                int rmCount = 0;  //需要数
                                double rmNeedWeight = 0.0;  //原料缺重
                                double rmTotalWeight = 0.0; //原料总重
                                if (type == 2) {  //为色粉的时候
                                    //算出来几袋
                                    rmCount = BigDecimal.valueOf((deficiencyWeight < 0.0 ? 0.0 : deficiencyWeight) / (EmptyUtils.isEmpty(rmMatl.getRmFmWg()) ? 1 : rmMatl.getRmFmWg())).setScale(0, RoundingMode.CEILING).intValue();
                                    reMatlNumber = rmCount - (int)rmStoke;//算出来库存够不够
                                } else {
                                    //比重
                                    double rmFmWg = EmptyUtils.isEmpty(rmMatl.getRmFmWg()) ? 0 : rmMatl.getRmFmWg();
                                    //换算单位 matlUnit 换算 成 rmMatl.getRmUnit()
                                    rmFmWg = parse(rmFmWg, toUnit(matlUnit), toUnit(rmMatl.getRmUnit()));
                                    //缺少订单的重量 rmFmWg = 比重 * lackPcs 订单缺数 * rmRadio 比数 - 库存
                                    rmTotalWeight = rmFmWg * lackPcs * rmMatl.getRmRadio();
                                    rmNeedWeight = rmTotalWeight - rmStoke;
                                }
                                double rmWeight = rmMatl.getRmWeight(); //单重
                                long issuingStatus = EmptyUtils.isNotEmpty(rmMatl.getIssuingStatus()) ? rmMatl.getIssuingStatus() : 0;
                                //判断 他不是未发料 就判断 他是不是色粉类型 是的话就不需要缺重  如果不是的话 就要算出来 缺重
                                rmMatl.setNeedWeight(issuingStatus != 0 ? 0 : type == 2 ? 0 : (rmNeedWeight < 0 ? 0 : rmNeedWeight));
                                ; //缺少重量
                                rmMatl.setLackPcs(Math.max(reMatlNumber, 0));    //缺少数量
                                rmMatl.setWeight(type == 2 ? 0 : rmTotalWeight<0 ?0 :rmTotalWeight);     // 订单数乘以每一个需要数乘以单重总重
                                //如果原料无缺数,并且没有创建发料单，就为无需发料,否者为空就等0 不为空就是原值
                                rmMatl.setIssuingStatus(orderPcs - fpPcs < 0 && EmptyUtils.isEmpty(rmMatl.getIssuingStatus()) ? 2 : EmptyUtils.isEmpty(rmMatl.getIssuingStatus()) ? 0 : rmMatl.getIssuingStatus());     //状态
                                //判断 类型是 1 的话就拿缺重来算是不是要采购   类型是2 的话就拿 缺数来算
                                rmMatl.setPurchaseStatus(type == 1 ? (rmNeedWeight < 0 ? 0L : 1L) : (reMatlNumber < 0 ? 0L : 1L));     //采购状态
                                rmMatl.setRmCount(rmCount); //需要几袋

                                //消耗总数
                                //rmMatl.setNeedTotal((int) (rmMatl.getRmRadio() * orderPcs));
                            }
                            List<TbMatlConsumables> matlConsumables = tbMatlConsumablesMapper.selectMatlConsumables(material.getId()); //物料下面的耗材
                            for (TbMatlConsumables tbMatlConsumables : matlConsumables) {
                                //订单缺数/ 比数  订单缺数除以比数
                                double count = new BigDecimal(Double.toString(material.getLackPcs())).doubleValue() / new BigDecimal(Double.toString(tbMatlConsumables.getQty())).doubleValue() / new BigDecimal(Double.toString(tbMatlConsumables.getCount())).doubleValue();
                                //向上取整
                                int qty = new BigDecimal(count).setScale(0, RoundingMode.CEILING).intValue();
                                TbConsumables consumables = tbMatlConsumables.getConsumables();  //耗材对象
                                tbMatlConsumables.setQty(qty); //耗材所需数量
                                consumables.setQty(qty); //耗材所需数量
                                //耗材缺数=所需数量 -库存
                                int lackQty = qty - consumables.getNumber();
                                //小于0 =0 否则就是缺数
                                consumables.setLackQty(Math.max(lackQty, 0));
                                //采购状态 耗材缺数 大于0 代表有缺数 需要采购
                                consumables.setPurchaseStatus(lackQty > 0 ? 1 : 0);
                                //发料状态
                                consumables.setIssuingStatus( orderPcs - fpPcs < 0 && EmptyUtils.isEmpty(consumables.getIssuingStatus()) ? 2 : EmptyUtils.isEmpty(consumables.getIssuingStatus()) ? 0 : consumables.getIssuingStatus());
                            }
                            material.setRawMatlList(rawMatlList);  //根据物料id查询下面的原材料
                            material.setMatlConsumablesList(matlConsumables);  //根据物料id查询下面的耗材

                            if (EmptyUtils.isNotEmpty(material.getOrderPcs()))
                                orderPcsTotal += material.getOrderPcs(); //加订单数
                        }
                        if (EmptyUtils.isNotEmpty(tbOrderMapper.tbOrderById(tbOrder.getId())))
                            tbOrder.setSelected(true);
                        tbOrder.setPlanNumber(orderPcsTotal);//计划数
                    }
                }


                //System.err.println(commandList);
//                for (TbCommand tb : iPage.getRecords()) {  //循环订单号
//                    List<TbCmdProd> tbCmdProds = listCmdProdListByCmdId(tb.getId());  //查询到指令号下面的生产计划
//                    int size = tbCmdProds.size();
//                    prodId = new Long[size];
//                    for (int tbCmdProdsIndex = 0; tbCmdProdsIndex < size; tbCmdProdsIndex++) { //循环生产计划
//                        prodId[tbCmdProdsIndex] = tbCmdProds.get(tbCmdProdsIndex).getProdId();  //拿到生产计划id
//                    }
//                    tb.setProdId(prodId); //用订单号算出生产计划数量
//                }
                return ResultUtil.success(ResultEnum.SUCCESS, records, iPage.getTotal()); //第二个参数 分页查询列表 第三个参数总数
            } else {
                return ResultUtil.error(ResultEnum.UNKONW_ERROR, zh_CH.MissingParameters);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ResultUtil.error(ResultEnum.UNKONW_ERROR);
    }

    /**
     * 删除指令信息
     *
     * @param command 指令信息
     * @return 结果
     */
    @Override
    @Transactional
    public Result<Object> deleteCommand(TbCommand command) {
        try {

            int deleteIdCount = 0; //删除数量
            Long id = command.getId();  //删除id
            if (EmptyUtils.isNotEmpty(id)) { //不等于空
                if (EmptyUtils.isNotEmpty(tbCmdOrderMapper.getCmdById(id))) { //查询生产计划
                    return ResultUtil.error(ResultEnum.UNKONW_ERROR, "生产计划在使用不能删除!");
                }
                List<TbCmdOrder> tbCmdProds = listTbCmdOrderByCmdId(id);
                //循环订单
                for (TbCmdOrder tbCmdProd : tbCmdProds)
                    deleteIdCount = deleteIdCount + tbCmdOrderMapper.deleteById(tbCmdProd.getId());
                if (tbCmdProds.size() == deleteIdCount && tbCommandMapper.deleteById(command.getId()) > 0) {  //判断删除数量跟原始
                    return ResultUtil.success(ResultEnum.SUCCESS, zh_CH.SuccessfullyDeleted);
                }
            } else {
                return ResultUtil.error(ResultEnum.UNKONW_ERROR, zh_CH.MissingParameters);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ResultUtil.success(ResultEnum.SUCCESS, zh_CH.FailedToDelete);
    }

    /**
     * 根据订单查询
     *
     * @param orderNumber
     * @return
     */
    @Override
    public Result<Object> getOrderNumber(String orderNumber) {
        try {
            QueryWrapper<TbOrder> qw = new QueryWrapper<>();
            qw.like("order_number", orderNumber);
            List<TbOrder> orderList = new CopyOnWriteArrayList(tbOrderMapper.selectList(qw));  //查询到订单 解决并发
            TbCommand command;
            for (TbOrder order : orderList) {
                if (order.getCheckOrder().equals(1L)) if (!order.getApprove().equals(1L)) orderList.remove(order);
                command = tbCommandMapper.getOrder(order.getOrderNumber());//拿到已用的指令号
                if (EmptyUtils.isNotEmpty(command)) {
                    order.setDisabled(true);
                    if (EmptyUtils.isNotEmpty(tbCmdOrderMapper.getCmdOrderById(order.getId())))
                        order.setSelected(true);
                }
            }
            return ResultUtil.success(ResultEnum.SUCCESS, orderList); //成功！
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ResultUtil.error(ResultEnum.UNKONW_ERROR);
    }

    /**
     * 生产指令号
     *
     * @param param
     * @return
     */
    @Override
    public Result<Object> productionCmdNumber(ClientParameters param) {
        try {
            String one = param.getOne(); //参数
            if (EmptyUtils.isNotEmpty(one)) {
                String username = Objects.requireNonNull(QuickQuery.byOne(sysUserMapper, "username", one)).getDivCode();
                return ResultUtil.success(ResultEnum.SUCCESS, cmdNumber(username));
            } else {
                return ResultUtil.error(ResultEnum.UNKONW_ERROR, zh_CH.MissingParameters);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ResultUtil.error(ResultEnum.UNKONW_ERROR);
    }

    /**
     * 生产指令号
     */
    public String cmdNumber(String createBy) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyMMdd");  //转换
        cmdNumberIndex = cmdNumberIndex + 1;  //自增
        return createBy + formatter.format(new Date()) + cmdNumberIndex;
    }

    /**
     * 根据订单id查询
     */
    @Override
    public List<TbCmdOrder> getByOrderId(Long orderId) {
        QueryWrapper<TbCmdOrder> query = new QueryWrapper<>();
        query.eq("oid", orderId);
        return tbCmdOrderMapper.selectList(query);
    }

    /**
     * 指令号唯一
     */
    public TbCommand checkCommandNumberUnique(String cmdNumber) {
        QueryWrapper<TbCommand> qw = new QueryWrapper<>();
        qw.eq("cmd_number", cmdNumber);
        return tbCommandMapper.selectOne(qw);
    }

    /**
     * 根据根据指令id查询订单
     *
     * @return
     */
    public List<TbCmdOrder> listTbCmdOrderByCmdId(Long cmdId) {
        QueryWrapper<TbCmdOrder> qw = new QueryWrapper<>();
        qw.eq("cmd_id", cmdId);
        return tbCmdOrderMapper.selectList(qw);
    }
}
